<template>
  <div class="top-area">
    <div class="city-choose">{{ city }}</div>
    <el-input
      placeholder="请搜索你所在的城市"
      @keyup.enter.native="handleInput"
      v-model="citySearch"
    ></el-input>
    <el-select
      placeholder="选择绘制图形"
      v-model="drawType"
      @change="handleDrawType"
      class="draw-type"
    >
      <el-option value="LineString" label="直线">直线</el-option>
      <el-option value="Circle" label="圆形">圆形</el-option>
      <el-option value="Polygon" label="多边形">多边形</el-option>
      <el-option value="FreeDraw" label="自由画笔">自由画笔</el-option>
      <el-option value="Clear" label="清除绘图">清除绘图</el-option>
    </el-select>
    <el-select
      placeholder="选择标记类型"
      v-model="iconType"
      @change="handleIconType"
      class="icon-type"
      :disabled="!isSelectedEnabled"
      :style="{ cursor: isSelectedEnabled ? 'pointer' : 'not-allowed' }"
    >
      <el-option value="charging" label="充电站">充电站</el-option>
      <el-option value="bus" label="公交站">公交站</el-option>
      <el-option value="parking" label="停车场"></el-option>
      <el-option value="stopMarker" label="退出制作标记"
        >退出制作标记</el-option
      >
    </el-select>
  </div>
  <div ref="overlayRef" class="overlay"></div>
  <div id="map" class="map-container"></div>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue'
import View from 'ol/View'
import Map from 'ol/Map'
import TileLayer from 'ol/layer/Tile'
import { XYZ } from 'ol/source'
import 'ol/ol.css'
import GeoJSON from 'ol/format/GeoJSON'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import Style from 'ol/style/Style.js'
import Fill from 'ol/style/Fill.js'
import Stroke from 'ol/style/Stroke.js'
import Overlay from 'ol/Overlay'
import Select from 'ol/interaction/Select'
import { singleClick } from 'ol/events/condition'
import Draw from 'ol/interaction/Draw.js'
import { getLength, getArea } from 'ol/sphere'
import LineString from 'ol/geom/LineString.js'
const mykey = '25b056a149aac2dfa269524533336b5a'
import Cluster from 'ol/source/Cluster.js'
import { CircleStyle, Text, Point } from 'ol/style.js'

//获取用户IP所在城市
import { getCityByIp, queryCityAdCode } from '../api'
let city = ref('')
let adcode = ref('')
let map = ref(null)
let source = ref(null)
let overlayRef = ref(null)
let citySearch = ref('')
let drawType = ref(null)
//draw是ol/interaction/Draw的实例
let draw = ref(null)
let drawLayer = ref(null)
let measureOverlay = ref(null)
let iconType = ref(null)
let icon = ref(null)
let iconLayer = ref(null)
let zoomlevel = ref(null)
let provinceData = ref(null)
let provinceFeatures = ref(null)
let iconArr = ref([])
let markerSource = ref(null)

const isSelectedEnabled = computed(() => {
  return zoomlevel.value >= 13
})

//根据用户输入的城市名称,查询adcode
const handleInput = (e) => {
  if (!source.value || source.value.getState() !== 'ready') {
    alert('地图数据尚未加载完成，请稍候重试')
    return
  }
  const value = e.target.value
  // console.log(value)
  if (value) {
    queryCityAdCode(value).then((res) => {
      console.log(res, 'queryCityAdCode')
      const result = res.geocodes[0].adcode
      console.log(result, '这是adcode')
      //根据adcode跟features匹配,获取目标城市
      const features = source.value.getFeatures()
      console.log(features, 'features')
      const targetCity = features.find((feature) => {
        // 确保数据类型匹配，都转换为字符串进行比较
        return String(feature.get('adcode')) === String(result)
      })
      if (targetCity) {
        console.log(targetCity, 'targetCity')
        const center = targetCity.values_.center
        //视口移动到目标城市,有动画效果,慢慢移动
        map.value.getView().animate({
          center: center,
          zoom: 10,
          duration: 2000,
        })
        //给目标城市添加一层vectorlayer,红色填充,黑色描边
        cityAddVectorLayer(targetCity)
      }

      //如果用户搜索的是省份,则显示该省份的城市数据
      const targetProvince = provinceData.value.find((province) => {
        return province.get('adcode') == String(result)
      })
      if (targetProvince) {
        console.log('找到省份')
        const center = targetProvince.get('center')
        map.value.getView().animate({
          center: center,
          zoom: 10,
          duration: 2000,
        })
        cityAddVectorLayer(targetProvince)
      }
    })
  }
}
//给目标城市添加一层vectorlayer,红色填充,黑色描边, 做成function
function cityAddVectorLayer(targetCityOrProvince) {
  const style = new Style({
    fill: new Fill({
      color: 'rgba(255, 0, 0, 0.5)',
    }),
    stroke: new Stroke({
      color: 'rgba(0, 0, 0, 1)',
      width: 2,
    }),
  })
  const vectorLayer = new VectorLayer({
    source: new VectorSource({
      features: [targetCityOrProvince],
    }),
    style: style,
  })
  map.value.addLayer(vectorLayer)
}

// 初始化地图
function initMap() {
  map.value = new Map({
    target: 'map',
    view: new View({
      projection: 'EPSG:4326',
      center: [114.25, 30.59],
      zoom: 4,
    }),
    layers: [],
  })

  measureOverlay.value = new Overlay({
    element: overlayRef.value,
    positioning: 'bottom-center',
  })
  //添加测量地图
  map.value.addOverlay(measureOverlay.value)

  //中国城市数据chinaLayer
  const chinaLayer = new VectorLayer({
    source: new VectorSource({
      url: 'https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json',
      format: new GeoJSON(),
    }),
  })
  map.value.addLayer(chinaLayer)

  //加载高德地图
  const gaodeLayer = new TileLayer({
    source: new XYZ({
      url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
    }),
  })
  map.value.addLayer(gaodeLayer)

  // 绘制图层
  drawLayer.value = new VectorLayer({
    source: new VectorSource(),
    style: new Style({
      stroke: new Stroke({ color: 'black', width: 2 }),
      fill: new Fill({ color: 'rgba(253, 149, 145,0.4)' }),
    }),
  })
  map.value.addLayer(drawLayer.value)

  //空的VectorSource用于存储标记Feature
  markerSource = new VectorSource()
  // 标记图层
  iconLayer.value = new VectorLayer({
    source: new Cluster({
      distance: 50,
      features: icons.value,
      source: markerSource,
    }),
    style: function (clutserFeature) {
      //聚合图层的关键是在于样式的设置
      //如果聚合在一起,可以显示成一个圆,在园中显示汇聚的数量
      //如果没有聚合在一起,显示一个置顶的icon
      const features = clutserFeature.get('features')
      const size = features.length
      //如果只有一个feature,则直接显示
      if (size == 1) {
        const singleFeature = features[0]
        let imgURL = ''
        if (markerType == 'charging') {
          imgURL = './charging.png'
        }
        if (markerType == 'bus') {
          imgURL = './bus/png'
        }
        if (markerType == 'parking') {
          imgURL = './parking.png'
        }
        return new Style({
          img: new Icon({
            src: imgURL,
            size: [32, 32],
            anchor: [16, 16],
          }),
        })
      } else {
        return new Style({
          image: new CircleStyle({
            radius: 20,
            fill: new Fill({
              color: 'purple',
            }),
          }),
          text: new Text({
            text: size.toString(),
            font: '18px sans-serif',
            fill: new Fill({
              color: 'white',
            }),
          }),
        })
      }
    },
  })
  map.value.addLayer(iconLayer.value)
  window.markerSource = markerSource

  // 定位到用户城市（第一次加载时候定位）
  const source = chinaLayer.getSource()
  let isLocated = false // 标志位，确保只定位一次
  source.on('change', function () {
    if (isLocated) return // 如果已经定位过，则直接返回
    const features = source.getFeatures()
    console.log('Features:', features)
    console.log('Target adcode:', adcode.value, typeof adcode.value)
    if (adcode.value) {
      const targetCity = features.find(
        (feature) => feature.values_.adcode == adcode.value
      )
      if (targetCity) {
        console.log(targetCity, 'targetCity')
        const center = targetCity.values_.center
        //视口移动到目标城市,有动画效果,慢慢移动
        map.value.getView().animate({
          center: center,
          zoom: 10,
          duration: 10,
        })
        //给目标城市添加一层vectorlayer,红色填充,黑色描边
        cityAddVectorLayer(targetCity)
        isLocated = true // 设置标志位，表示已经定位过
      }
    }
  })

  // 为地图添加一次点击事件监听器，用于添加标记
  map.value.on('click', function (e) {
    // 只有在选择了有效的图标类型时才添加标记
    if (iconType.value && iconType.value !== 'stopMarker') {
      addMarker(e.coordinate, iconType.value)
    }
  })

  //如果点击的是目标城市,可以触发事件,添加overlay,显示城市名字和经纬度信息
  const select = new Select({
    condition: singleClick,
    layers: [chinaLayer],
  })
  map.value.addInteraction(select)

  const cityOverlay = new Overlay({
    element: document.querySelector('.overlay'),
    positioning: 'bottom-center',
  })
  map.value.addOverlay(cityOverlay)

  select.on('select', function (e) {
    //点击城市,显示城市名字和经纬度信息
    let feature = e.selected[0]
    //可以读到feature
    // console.log(feature)
    if (feature) {
      let center = feature.get('center')
      cityOverlay.setPosition(center)
      //设置overlay的内容
      let name = feature.get('name')
      let adcode = feature.get('adcode')
      let longitude = center[0]
      let latitude = center[1]
      let element = document.querySelector('.overlay')
      element.innerHTML = `<p>当前的城市是${name}</p><p>经度:${longitude}</p><p>纬度:${latitude}</p>`
    }
    //如果没有选中要素,则设置undefined,清空overlay的内容
    else {
      cityOverlay.setPosition(undefined)
    }
  })

  return chinaLayer.getSource()
}

// 在onMounted中执行异步操作
onMounted(async () => {
  // 初始化地图
  source.value = initMap()
  // 获取城市信息（异步操作）
  let res = await getCityByIp()
  console.log(res, 'res')
  city.value = res.city
  adcode.value = res.adcode
  console.log(city.value, adcode.value)

  //获取省份数据
  const provinceUrl =
    'https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json'
  const response = await fetch(provinceUrl)
  const data = await response.json()
  provinceData.value = data.features.map((rawFeature) => {
    return new GeoJSON().readFeature(rawFeature, {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:4326',
    })
  })
  console.log(provinceData.value, '省份数据')

  //需要时刻更新zoomlevel的值
  //如果zoomlevel小于13,则制作标记的el-input鼠标移上去显示的不是pointer,而是禁止标志,不可以选择
  //如果zoomlevel大于13,则制作标记的el-input鼠标移上去显示是add,可以选择
  zoomlevel.value = map.value.getView().getZoom()
  map.value.on('moveend', function () {
    zoomlevel.value = map.value.getView().getZoom()
    console.log(zoomlevel.value, 'zoomlevel')
    if (zoomlevel.value < 13) {
      document.querySelector('.icon-type').style.cursor = 'not-allowed'
    } else {
      document.querySelector('.icon-type').style.display = 'block'
    }
  })
})

const icons = iconArr.value.map(
  (icon) => new Feature({ geometry: new Point(icon.coords), name: icon.name })
)

//根据用户在drawType的选择, 绘制相应的图形
function handleDrawType(value) {
  console.log(value, 'drawType')
  if (draw.value) {
    map.value.removeInteraction(draw.value)
    draw.value = null
  }
  // 清除绘图逻辑
  if (value === 'Clear') {
    if (drawLayer.value) {
      drawLayer.value.getSource().clear() // 清空所有绘制内容
      return
    }
  }
  // 处理不同绘图类型
  let type = value
  let freehand = false
  // 自由画笔特殊处理
  if (value === 'FreeDraw') {
    type = 'LineString'
    freehand = true
  }
  // 创建绘图交互并添加到地图
  draw.value = new Draw({
    source: drawLayer.value.getSource(),
    type: type,
    freehand: freehand,
  })
  map.value.addInteraction(draw.value)
  //把要显示的长度或者面积的overlay添加到地图
  //如果是直线,需要在末端显示一个overlay,显示当前的长度
  if (type === 'LineString') {
    draw.value.on('drawend', (e) => {
      let f = e.feature
      let g = f.getGeometry()
      // 使用正确的单位计算长度 (米)
      let length = getLength(g, { projection: 'EPSG:4326' })
      console.log('Line length:', length)
      let position = g.getLastCoordinate()
      // 更新overlay内容和位置
      if (measureOverlay.value) {
        measureOverlay.value.getElement().innerHTML = `当前长度为${(
          length / 1000
        ).toFixed(2)}km`
        measureOverlay.value.setPosition(position)
      }
    })
  }

  //如果是圆形,需要在圆心显示一个overlay,显示面积
  if (type === 'Circle') {
    draw.value.on('drawend', (e) => {
      let f = e.feature
      let g = f.getGeometry()
      // 对于圆形，需要特殊处理计算面积
      // 获取圆心和圆周上的一个点
      let center = g.getCenter()
      let radius = g.getRadius()
      // 计算圆周上的一个点（东边的点）
      let edgePoint = [center[0] + radius, center[1]]
      // 使用getLength计算实际的地理距离（半径）
      let actualRadius = getLength(new LineString([center, edgePoint]), {
        projection: 'EPSG:4326',
      })
      // 使用实际半径计算面积
      let area = Math.PI * actualRadius * actualRadius
      console.log('Circle area:', area)

      // 更新overlay内容和位置
      if (measureOverlay.value) {
        measureOverlay.value.getElement().innerHTML = `当前面积为${(
          area / 1000000
        ).toFixed(2)}平方公里`
        measureOverlay.value.setPosition(center)
      }
    })
  }
  //如果是多边形,需要在最后一个点显示一个overlay,显示面积
  if (type === 'Polygon') {
    draw.value.on('drawend', (e) => {
      let f = e.feature
      let g = f.getGeometry()
      // 使用正确的API计算面积
      let area = getArea(g, { projection: 'EPSG:4326' })
      console.log('Polygon area:', area)
      // 获取多边形的中心点作为显示位置
      let extent = g.getExtent()
      let center = [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2]
      // 更新overlay内容和位置
      if (measureOverlay.value) {
        measureOverlay.value.getElement().innerHTML = `当前面积为${(
          area / 1000000
        ).toFixed(2)}平方公里`
        measureOverlay.value.setPosition(center)
      }
    })
  }
}
//改变iconType时,更新iconLayer的样式
function handleIconType(value) {
  console.log(value, 'iconType')
  // 设置当前选择的图标类型
  iconType.value = value
}

// 添加标记的函数
function addMarker(coordinate, type) {
  const pointGeometry = new Point(coordinate)
  //创造feature对象
  const markerFeature = new Feature({
    geometry: pointGeometry, // 绑定几何坐标
    type: type, // 存储标记类型（用于样式函数识别）
    name: type, // 可选：存储额外信息
  })

  const markerSource = window.markerSource

  if (markerSource) {
    markerSource.addFeature(markerFeature)
  }
}
</script>

<style lang="scss" scoped>
.top-area {
  height: 80px;
  background-color: #4264fb;
  position: fixed;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 100px;

  .city-choose {
    margin-inline: 50px;
    color: #fff;
  }

  :deep(.el-input) {
    width: 240px;
    font-size: 14px;
    box-sizing: border-box;
    display: inline-flex;
    position: relative;
    vertical-align: middle;
  }

  :deep(.el-select) {
    width: 240px;
    font-size: 14px;
  }

  :deep(.el-input.is-disabled) {
    cursor: not-allowed;
  }
}

.map-container {
  width: 100%;
  height: calc(100vh - 80px);
  position: relative;
  top: 80px;
}
</style>
